#include "my_thread_base.h"

static my_thread_key_t      thread_local_key = (my_thread_key_t)(-1);


__attribute((constructor)) static void
my_thread_local_key_init()
{
    my_thread_key_create(&thread_local_key, NULL);
}


static inline void *
my_thread_base_runner(void *arg)
{
    void *ret = NULL;
    my_thread_base_t    *thread_base = (my_thread_base_t *)arg;
    my_thread_setspecific(thread_local_key, thread_base);
    ret = thread_base->execute_pt(thread_base);

    return ret;
}


void
my_thread_base_start(
    const char *tag,
    my_thread_base_t *thread_base,
    my_thread_base_execute_pt execute_pt,
    void *data,
    int64_t mem_freelists_level,
    int64_t aligned_mem_freelists_level)
{
    thread_base->tag = tag;
    thread_base->execute_pt = execute_pt;
    thread_base->data = data;

    if (mem_freelists_level > 0) {
        thread_base->mem_freelists
            = my_thread_mem_freelists_create(mem_freelists_level);
    }

    if (aligned_mem_freelists_level > 0) {
        thread_base->aligned_mem_freelists
            = my_thread_4kaligned_mem_freelists_create(aligned_mem_freelists_level);
    }

    thread_base->tid = my_thread_create(my_thread_base_runner, thread_base, MY_FALSE);
}


void
my_thread_base_join(my_thread_base_t *thread_base, void **ret)
{
    my_thread_join(thread_base->tid, ret);

    if (thread_base->mem_freelists) {
        my_thread_mem_freelists_destroy(thread_base->mem_freelists);
    }

    if (thread_base->aligned_mem_freelists) {
        my_thread_4kaligned_mem_freelists_destroy(thread_base->aligned_mem_freelists);
    }
}


my_thread_base_t *
current_thread_base()
{
    my_thread_base_t *thread_base
        = my_thread_getspecific(thread_local_key);
    return thread_base;
}


void *
my_thread_malloc(size_t size)
{
    my_thread_base_t *thread_base = current_thread_base();
    if (thread_base && thread_base->mem_freelists) {
        return my_thread_mem_freelists_alloc(thread_base->mem_freelists, size);
    }

    return my_mem_alloc(size);
}


void
my_thread_free(void *ptr)
{
    my_thread_base_t *thread_base = current_thread_base();
    if (thread_base && thread_base->mem_freelists) {
        return my_thread_mem_freelists_free(thread_base->mem_freelists, ptr);
    }

    return my_mem_free(ptr);
}


void *
my_thread_aligned_malloc(size_t size)
{
    my_thread_base_t *thread_base = current_thread_base();
    if (thread_base && thread_base->aligned_mem_freelists) {
        return my_thread_4kaligned_mem_freelists_alloc(thread_base->aligned_mem_freelists, size);
    }

    return my_4kaligned_mem_alloc(size);
}


void my_thread_aligned_free(void *ptr)
{
    my_thread_base_t *thread_base = current_thread_base();
    if (thread_base && thread_base->aligned_mem_freelists) {
        return my_thread_4kaligned_mem_freelists_free(thread_base->aligned_mem_freelists, ptr);
    }

    return my_4kaligned_mem_free(ptr);
}